package com.iphaeton.persistence.hibernate;

import com.iphaeton.exception.PersistenceException;
import com.iphaeton.persistence.IPersistenceService;
import com.iphaeton.persistence.PersistentObject;
import java.sql.Connection;
import java.util.List;
import org.apache.commons.beanutils.BeanUtils;
import org.apache.log4j.Logger;
import org.hibernate.HibernateException;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
import org.hibernate.dialect.Dialect;

public class HibernatePService implements IPersistenceService {
	private static Logger logger = Logger.getLogger(HibernatePService.class);
	private static SessionFactory sessionFactory;
	public static SessionFactory getSessionFactory() {
		return sessionFactory;
	}

	

	private static Dialect currDialect;
	private static final ThreadLocal localSession = new ThreadLocal();

	public HibernatePService() {
		try {
			Configuration conf = new Configuration().configure();
			sessionFactory = conf.buildSessionFactory();
			currDialect = Dialect.getDialect(conf.getProperties());
		} catch (HibernateException e) {
			e.printStackTrace();
			throw new RuntimeException("Exception on building SessionFactory: "
					+ e.getMessage(), e);
		}
	}

	public HibernatePService(SessionFactory sessionFactory) {
		this.sessionFactory = sessionFactory;
	}

	private Session getSession() {
		Session ses = (Session) localSession.get();
		try {
			if (ses == null) {
				
				
				ses = sessionFactory.openSession();
				ses.connection().setAutoCommit(false);

				localSession.set(ses);
			} else if (ses.connection().isClosed()) {
				localSession.set(null);
				ses = sessionFactory.openSession();
				ses.connection().setAutoCommit(false);

			}
			localSession.set(ses);
		} catch (Exception e) {
			e.printStackTrace();
			throw new RuntimeException("Error on getting session!");
		}

		label108: return ses;
	}

	public PersistentObject store(PersistentObject po)
			throws PersistenceException {
		if (po == null)
			throw new PersistenceException(
					"HibernatePService, null ojbect is passed in!");
		Session ses = getSession();
		try {
			if ((po.getId() == null) || (po.getId().trim().equals(""))) {
				ses.save(po);
			} else {
				ses.update(po);
			}

			if (!ses.contains(po)) {
				PersistentObject vo = (PersistentObject) ses.load(
						po.getClass(), po.getId());
				BeanUtils.copyProperties(po, vo);
				po = vo;
			}

		} catch (Throwable te) {
			throw new PersistenceException(
					"Error on storing persistent object!", te);
		}

		label109: return po;
	}

	public PersistentObject get(String id, Class cls)
			throws PersistenceException {
		if (id == null)
			throw new PersistenceException(
					"HibernatePService.null is not a valid Id!");

		if (cls == null)
			throw new PersistenceException(
					"HibernatePService.null is not a valid Class!");

		PersistentObject po = null;
		try {
			po = (PersistentObject) getSession().get(cls, id);
		} catch (HibernateException e) {
			String msg = "HibernatePService.exception on loading persistent object by Id,Class";
			logger.error(msg, e);
			throw new PersistenceException(e);
		}
		return po;
	}

	public void remove(PersistentObject po) throws PersistenceException {
		try {
			if (po.getId() == null)
				return;
			getSession().delete(po);
			getSession().flush();
		} catch (HibernateException e) {
			String msg = "HibernatePService, exception on removing persistent object";
			logger.error(msg, e);
			throw new PersistenceException(msg, e);
		}
	}

	public void remove(String id, Class cls) throws PersistenceException {
		PersistentObject po;
		if (id == null)
			throw new PersistenceException(
					"HibernatePService.null is not a valid Id!");

		if (cls == null)
			throw new PersistenceException(
					"HibernatePService.null is not a valid Class!");

		try {
			po = (PersistentObject) getSession().load(cls, id);
			remove(po);
		} catch (HibernateException e) {
			String msg = "HibernatePService.exception on removing by Id,Class";
			logger.error(msg, e);
			throw new PersistenceException(e);
		}
	}

	public List query(String query) throws PersistenceException {
		try {
			if (query.indexOf("$") > -1)
				query = query.replaceAll("\\$\\d+", "\\?");
			Query q = getSession().createQuery(query);
			return q.list();
		} catch (Throwable e) {
			String msg = "HQL 查询语句有误！";
			e.printStackTrace();
			logger.error(msg, e);
			
			throw new PersistenceException(msg, e);
		}
	}

	public List query(String query, int startItemPos, int maxItemNum)
			throws PersistenceException {
		if (query == null)
			throw new PersistenceException("null query string isn't permitted!");

		try {
			if (query.indexOf("$") > -1)
				query = query.replaceAll("\\$\\d+", "\\?");

			if ((startItemPos >= 0) && (maxItemNum > 0)) {
				Query hbQuery = getSession().createQuery(query);
				hbQuery.setFirstResult(startItemPos);
				hbQuery.setMaxResults(maxItemNum);
				return hbQuery.list();
			}
			return query(query);
		} catch (Throwable e) {
			String msg = "HibernatePService HSQL specified query error！";
			logger.error(msg, e);
			throw new PersistenceException(msg, e);
		}
	}

	public void begin() throws PersistenceException {
		getSession();
	}

	public void commit() throws PersistenceException {
		try {
			if (localSession.get() == null)
				return;
			getSession().flush();

			if (getSession().connection().getAutoCommit())
				return;
			getSession().connection().commit();
		} catch (Throwable te) {
			String msg = "ERROR on committing transaction!";
			logger.error(msg, te);
			throw new PersistenceException(te);
		}
	}

	public void rollback() throws PersistenceException {
		try {
			if (getSession().connection().getAutoCommit())
				return;
			getSession().connection().rollback();
		} catch (Throwable te) {
			String msg = "ERROR during rollback";
			logger.error(msg, te);
			throw new PersistenceException(msg, te);
		}
	}

	public void release() throws PersistenceException {
		Session ses = (Session) localSession.get();

		if (ses == null)
			return;
		localSession.set(null);

		if (ses != null)
			try {
				if (ses.isOpen()) {
					ses.close();
				}

			} catch (Throwable te) {
				String msg = "ERROR on cleaning up Hibernate session";
				logger.error(msg, te);
				throw new PersistenceException(msg, te);
			}

		ses = null;
	}
}